package com.gitee.feizns.quickstart.web.spring.boot.autoconfigure;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.feizns.quickstart.web.advice.JsonPathFilterResponseBodyAdvice;
import com.gitee.feizns.quickstart.web.converter.EnumValueConverterFactory;
import com.gitee.feizns.quickstart.web.converter.StringToEnumsIgnoreCaseConverterFactory;
import com.gitee.feizns.quickstart.web.converter.ToDateConverterFactory;
import com.gitee.feizns.quickstart.web.converter.ToTemporalAccessorConverterFactory;
import com.gitee.feizns.quickstart.web.cross.Cross;
import com.gitee.feizns.quickstart.web.filter.CachingRequestBodyFilter;
import com.gitee.feizns.quickstart.web.resolver.JsonParameterResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * web环境常用配置类
 */
@EnableConfigurationProperties(QuickstartWebProperties.class)
public class QuickstartWebAutoConfiguration {

    @Autowired
    private QuickstartWebProperties properties;

    /**
     * 缓存请求正文过滤器
     * @return {@link FilterRegistrationBean }<{@link CachingRequestBodyFilter}>
     */
    @Bean
    @ConditionalOnMissingBean(CachingRequestBodyFilter.class)
    public FilterRegistrationBean<CachingRequestBodyFilter> cachingRequestBodyFilter() {
        FilterRegistrationBean<CachingRequestBodyFilter> reg = new FilterRegistrationBean<>();
        reg.setFilter(new CachingRequestBodyFilter(
                MediaType.APPLICATION_JSON,
                MediaType.APPLICATION_XML,
                MediaType.TEXT_PLAIN,
                MediaType.TEXT_HTML,
                MediaType.APPLICATION_FORM_URLENCODED));
        reg.addUrlPatterns("/*");
        reg.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return reg;
    }

    /**
     * 全局响应包装（处理json结构过滤）
     * @return {@link JsonPathFilterResponseBodyAdvice }
     */
    @Bean
    @ConditionalOnMissingBean
    public JsonPathFilterResponseBodyAdvice globalResponseAdvice() {
        return new JsonPathFilterResponseBodyAdvice();
    }

    /**
     * Web MVC 自动配置器
     * @param objectMapper 对象映射器
     * @return {@link WebMvcConfigurer }
     */
    @Bean
    public WebMvcConfigurer webMvcAutoConfigurer(ObjectMapper objectMapper) {
        return new WebMvcConfigurer() {



            /**
             * 让 Spring boot 配置文件支持跨域的配置
             * <p>
             *     在 application.properties 中可以做这样的配置
             * </p>
             * <pre>{@code
            quickstart.web.cross[0].mapping=/**
            quickstart.web.cross[0].allow-origin-patterns=*
            #quickstart.web.cross[0].allow-origins=*
            quickstart.web.cross[0].allow-methods=*
            quickstart.web.cross[0].allow-headers=*
            quickstart.web.cross[0].allow-credentials=true
             * }</pre>
             * @see Cross
             * @see QuickstartWebProperties
             * @param registry {@link CorsRegistry}
             */
            @Override
            public void addCorsMappings(@NonNull CorsRegistry registry) {
                Cross cross = properties.getCross();
                registry.addMapping(cross.getMapping())
                        .allowedOrigins(cross.getAllowOrigins())
                        .allowedMethods(cross.getAllowMethods())
                        .allowedHeaders(cross.getAllowHeaders())
                        .allowedOriginPatterns(cross.getAllowedOriginPatterns())
                        .allowCredentials(cross.isAllowCredentials());
            }

            /**
             * @param registry {@link FormatterRegistry}
             */
            @Override
            public void addFormatters(@NonNull FormatterRegistry registry) {
                ToTemporalAccessorConverterFactory
                        .supportJava8DateTypesConverters()
                        .forEach(registry::addConverter);
                ToDateConverterFactory.dateConverters()
                        .forEach(registry::addConverter);
                //枚举字符转换映射 EnumValue
                registry.addConverterFactory(new EnumValueConverterFactory());
                if ( properties.isEnumsIgnoreCase() )
                    registry.addConverterFactory(new StringToEnumsIgnoreCaseConverterFactory());
            }

            /**
             * 添加了对@Json的参数解析器
             * @param resolvers {@link HandlerMethodArgumentResolver}
             */
            @Override
            public void addArgumentResolvers(@NonNull List<HandlerMethodArgumentResolver> resolvers) {
                resolvers.add(new JsonParameterResolver(objectMapper));
            }
        };
    }

}
